8 拦截器(interceptor)
8.1 Struts架构图
8.2 Struts执行过程分析
- 拦截器:拦截器是struts2框架中提供的一种Java类
- 作用:
* 可以拦截访问Action的请求 * 给这个Action加上新的丰富功能(上传,参数自动接收,类型自动转换等)需要配置之后,指明哪一个拦截器去拦截哪一个Action或者哪一些Action,这个拦截器才会去拦截我们的Action。
- 拦截器工作原理:
1. 有一个拦截器的类(框架的或者自定义的) 2. 在配置文件中把这个拦截器类配置出来 3. 指明这个拦截器要拦截哪一个或者哪一些action 4. 客户端发送一个请求访问一个被拦截器拦截的Action 5. 这个请求首先会被struts2 的filter所拦截,filter会检查这个请求是不是请求的Action,如果是,会再检查这个Action有没有被定义的拦截器所拦截,如果有,那么把这个请求交给拦截器去处理
8.3 Interceptor拦截器过程模拟
- 定义一个Interceptor接口,有一个intercept方法。
|
|
- 创建两个interceptor实现了interceptor接口:
|
|
|
|
- 定义一个Action
|
|
- 定义ActionInvocation
|
|
- 执行main文件:
|
|
- 运行结果为:
|
|
从而执行顺序为,首先main函数,创建ActionInvocation对象,初始化的时候讲两个Inteceptor加到interceptors这个列表中,调用其invoke()方法,当还有interceptor没有访问时,调用第一个interceptor的intercept方法,输出1,并调用ActionInvocation的invoke方法,此时会调用第二个Inteceptor的intercept方法,输出2,并调用ActionInvocation的invoke方法,此时不存在拦截器,执行Action输出execute,后面依次输出-2 -1, 完成这个模拟过程!
8.4 定义自己的拦截器
struts2框架已经写好了很多个拦截器,同时也把这些拦截器配置在配置文件里面struts-default.xml中,除此之外,我们可以写自己的拦截器
首先实现一个Interceptor接口:
|
|
- 然后在struts.xml文件中配置出这个拦截器:
|
|
8.5 拦截器栈
当一个Action需要被多个拦截器拦截的时候,正常情况下我们需要在这个Action中去引用要使用的多个拦截器,但是我们可以使用一个拦截器栈去包含那几个拦截器,然后直接在Action中引用这个拦截器栈就可以。
- 一个拦截器栈可以包含多个拦截器
- 一个拦截器栈还可以包含其他拦截器栈
- 定义拦截器栈都要在
标签中
|
|
8.6 默认拦截器栈/拦截器
在一个package中,我们可以把一个拦截器或者拦截器栈的声明为一个默认的拦截器/拦截器栈。以后这个package中所有的Action都会被这个默认的拦截器/拦截器栈所拦截
- 我们写的任何Action都会被一个叫做defaultStack的拦截器栈所拦截,这个拦截器栈包含了十几个拦截器,这些拦截器给我们的Action提供了很多丰富的功能,因为我们写的所有的package都是直接或者间接继承了struts-default.xml文件中的一个名字叫struts-default的package, struts-default包中又把名字叫做defaultStack的拦截器栈配置成了一个默认的拦截器栈,我们的package继承了这个,所有的Action都会被defaultStack所拦截。
- 但是如果我们指明了一个Action被我们所写的一个拦截器/拦截器栈所拦截,name这个Action就不会被defaultStack拦截了,所以我们需要在Action中主动的在声明这个Action被defaultStack所拦截,或者把defaultStack加入到我们自己定义的拦截器栈里面。
- 也可以专门定义一个package专门定义拦截器,拦截器栈,其他package继承这个拦截器栈package:
|
|
8.7 类型转换
类型转换:解析HTTP请求参数,将HTTP请求参数赋值给Action属性,当其类型不一致时进行的类型转换操作。struts2完成了String和基本类型的类型转换,只要Action属性有get set 方法。同时其还支持自定义的类型转换。
struts2类型转换时通过Params拦截器进行转换的;如果转换失败,则conversionError拦截器拦截该异常,并封装到fieldError中,放入ActionContext中。
8.7.1 基础类型转换:
testAction:
|
|
test.jsp:
|
|
8.7.2自定义类型转换
自定义类型转换器方法:
继承DefaultTypeConverter,重写convertValue方法,这个方法的功能是完成双向转换,Sting数组转换到Action属性。函数模板为:
|
|
继承StrutsTypeConverter
- StrutsTypeConverter是DefaultTypeConverter的子类。在两个方向的类型转换上分别实现:
MyPointerConverter:
|
|
TestAction:
|
|
jsp:
|
|
注册方式:
- 第一种配置方法为在具备类型转换文件中配置,局部类型转换文件命名为
ActionName-conversion.properties
,位置放在特定的Action目录下,文件内容格式为:typeName=ConverClass
仅针对特定的Action的特定属性有效 - 第二种配置方法为全局类型转换文件中红配置,文件名为xwork-conversion.properties,在
WEB-INF\classes
下,文件内容格式为:attributeName=ConvertClass
, 对某个类型都有效,比如对Point类型注册了类型转换器。 注解
8.8 拦截器和过滤器的比较
- 相同点:
- 都是一种Java类
- 都能拦截客户端发给服务端的请求
- 拦截到请求之后都可以做一些相应的处理,最后还可以把这个请求放行
- 都需要实现各自相应的接口记忆在相应的配置文件中配置
不同点:
- 拦截器是Struts2框架中定义的,过滤器是web里面的对象,是J2EE标准定义的
- 拦截器只会拦截访问Action的请求,过滤器可以拦截所有的请求
- 拦截器定义在struts.xml文件中,过滤器定义在web.xml中
- 拦截器对象的创建、调用、销毁时struts2框架负责的,过滤器对象的创建、调用、销毁时服务器负责的。
我们自己定义的filter也可以拦截struts2框架中的Action,需要在web.xml文件中把我们自己的filter配置在struts2的filter上面才可以,因为web.xml文件中的filter配置的先后顺序控制filter起作用的顺序,如果struts的filter先拦截到访问action的请求后,不会把这个请求交给下面的filter,而是交给它内部的拦截器。如果我们自己的filter拦截到请求之后,还是会交给下一个filter,也就是交给struts2的filter
9 注解Annotation
9.1 注解使用方式
- 引入支持struts2框架注解开发的jar包 struts2-convention-plugin-2.3.4.1
- struts.xml
<constant name="struts.convention.action.suffix" value="Action"/>
Struts2使用注解开发需要遵循一定的规范:
- Action要必须继承ActionSupport父类
- Action所在的包名必须以Action结尾
- package-info.java 在这里配置这个包下所有的类都可以用
123456@Namespace("/")@ParentPackage("struts-default")@DefaultInterceptorRef("authStack")//authStack自定义的拦截器package com.briup.action.manager;import org.apache.struts2.convention.annotation.Namespace;import org.apache.struts2.convention.annotation.ParentPackage;
9.2 Action常用注解
Namespace Annotation
- 通过在ActionClass上定义@Namespace(“/custom”)
- 通过package0info.java定义1234@Namespace("/manager")@ParentPackage("default")@DefaultInterceptorRef("authStack")package com.example.actions;
Action Annotation
1234567891011121314151. @Action(interceptorRefs={@InterceptorRef("validation"),@InterceptorRef("defaultStack")})2. chain@Action("foo")public String foo() {return "bar";}@Action("foo-bar")public String bar() {return SUCCESS;}Result Annotation
- 全局, 整个类可以访问
- 局部, 某个方法可以访问123456789@Results({@Result(name="failure", location="fail.jsp")})public class HelloWorld extends ActionSupport {@Action(value="/different/url",results={@Result(name="success", location="http://struts.apache.org", type="redirect")} )public String execute() {return SUCCESS;}}